#include "../opcode.h"
#include "../service.h"

#include "gateway.h"
#include "gateServer.h"

Gateway::Gateway(int socket, char* ip, uint16 port)
: Connection(SOCKET_TYPE_TCP, socket)
, m_ip(NULL)
, m_port(port)
, m_state(STATE_NONE)
, m_bIsAliveInServer(true)
{
	if(ip != NULL)
		m_ip = StringNew(ip);

	m_serviceManager = SAFE_NEW ServiceManager(this);
}

Gateway::~Gateway()
{
	SAFE_DELETE_ARRAY(m_ip);
	SAFE_DELETE(m_serviceManager);
}

int Gateway::Update()
{
	HandleNetPacket();

	m_serviceManager->Update();

	switch(m_state)
	{
	case STATE_CLOSING_SERVICE:
		if(m_serviceManager->Empty())
			SetState(STATE_CLOSED);
		break;

	case STATE_CLOSED:
		{
			LogoutResult result = sGateServer.Logout(m_uid, this);
			if(LOGOUTRESULT_SUCCESS != result)
			{
				LOGOUT("%s logout failed, error code : %d\n", GetUid().c_str(), result);
			}

			m_bIsAliveInServer = false;
		}
		break;

	case STATE_RUN:
		break;

	default:
		break;
	}

	return 0;
}

void Gateway::ClosePacket()
{
	NetPacket packet(Def::OPCODE_CS_LOGOUT);

	m_recvQueue.Enqueue(packet);
}

bool Gateway::SendPacket()
{
	if(!m_sendQueue.IsEmpty())
	{
		NetPacket sendPacket;
		if(m_sendQueue.Dequeue(sendPacket) != 0)
			return false;

		bool success = Send((const char*)sendPacket.Data(), sendPacket.Size());
		if(success)
			return true;
		else
			return false;
	}

	return true;
}

void Gateway::RecvPacket()
{
	Recv();
	ToNetPacket();
}

void Gateway::ToNetPacket()
{
	while(m_recvBuffer.length() > NET_PACKET_OFFSET)
	{
		const char* data = m_recvBuffer.c_str();
		int lenData = m_recvBuffer.length();

		uint16 bodySize = 0;
		memcpy((uint8*)&bodySize, data, 2);
		bodySize = ntohs(bodySize);

		if(m_recvBuffer.length() >= bodySize)
		{
			NetPacket recvPacket;
			recvPacket.DecodePacket((const uint8*)data, bodySize);
			m_recvQueue.Enqueue(recvPacket);

			m_recvBuffer = m_recvBuffer.substr(bodySize);
		}
	}
}

bool Gateway::SendSelectPacket()
{
	if(send_select())
		return SendPacket();

	return false;
}

void Gateway::RecvSelectPacket()
{	
	RecvSelect();
	ToNetPacket();
}

int Gateway::HandleNetPacket()
{
	if(m_recvQueue.IsEmpty()) return HANDLE_PACKET_NONE;

	NetPacket recvPacket;
	if(m_recvQueue.Dequeue(recvPacket) != 0)
		return HANDLE_PACKET_INVAILD;

	uint16 opcode = recvPacket.GetOpcode();
	if (sHanlderMap.count(opcode) == 0)
	{
		ELOG("Received unhandled opcode[0x%.4X : %s], uid[%s]", opcode, OPCODE2NAME(opcode), GetUid().c_str());
		return HANDLE_PACKET_NOREG_OPCODE;
	}

	try
	{
		if(sHanlderMap[opcode]->Execute(this, recvPacket) < 0)
			return HANDLE_PACKET_ERROR;
	}
	catch(...)
	{
		ELOG("Invalid packet format opcode[0x%.4X : %s], uid[%s]", opcode, OPCODE2NAME(opcode), GetUid().c_str());
		return HANDLE_PACKET_FORMAT_DONOT_MATCH;
	}

	return HANDLE_PACKET_NONE;
}

int Gateway::ExecutePacket(NetPacket& packet)
{
	vector<string> params; params.clear();
	return m_serviceManager->CallService(OPCODE2SERVICE(packet.GetOpcode()), params, &packet);
}

void Gateway::PushSendPacket(NetPacket& packet, BlockTree* tree)
{
	if(tree != NULL)
		tree->FillUpNetPacket(packet);

	packet.EncodePacket();
	m_sendQueue.Enqueue(packet);
}